home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / (A)TB / (A)TBQ.ADF / CLI_only / DT.Source / dt.c next >
C/C++ Source or Header  |  1991-09-15  |  10KB  |  378 lines

  1. #define VERSION       1.10
  2. #define LAST_CHANGED  900924
  3.  
  4. /*--------------------------------------*
  5.  | File: DT.c - Rev. 1.10 900924        |
  6.  +--------------------------------------+
  7.  | DT: disk test, a la Norton Utilities |
  8.  +--------------------------------------+---------------*
  9.  | Author: Maurizio Loreti, aka MLO or I3NOO.           |
  10.  | Address: University of Padova - Deparment of Physics |
  11.  |          Via F. Marzolo, 8 - 35131 PADOVA - Italy    |
  12.  | Phone: (39)(49) 844-313        FAX: (39)(49) 844-245 |
  13.  | E-Mail: LORETI at IPDINFN (BITNET) or VAXFPD::LORETI |
  14.  |         (DECnet). VAXFPD is node 38.257, i.e. 39169. |
  15.  | Home: Via G. Donizetti, 6 - 35010 CADONEGHE (Padova) |
  16.  *------------------------------------------------------*/
  17.  
  18. /**
  19.  | #include's
  20. **/
  21.  
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <stdarg.h>
  26. #include <dos.h>
  27. #include <exec/types.h>
  28. #include <exec/exec.h>
  29. #include <devices/trackdisk.h>
  30. #include "mlo.h"
  31.  
  32. /**
  33.  | #define's. The first two should be in TRACKDISK.H, the fourth in
  34.  | STDIO.H for ANSI compilers - but are not there in the Lattice
  35.  | Include files. TD_CYL is the number of bytes per cylinder.
  36. **/
  37.  
  38. #define NUMCYLS       80
  39. #define NUMHEADS      2
  40. #define TD_CYL        (TD_SECTOR * NUMSECS)
  41. #define FILENAME_MAX  108
  42. #define ON            1
  43. #define OFF           0
  44.  
  45. /**
  46.  | A structure definition for directory entries; for Lattice C, only one
  47.  | call to dfind/dnext can be active at a time: so, scanning directories,
  48.  | we check all files first and, only then, all subdirectories one by one.
  49. **/
  50.  
  51. typedef struct sdirEntry {
  52.   char *name;
  53.   struct sdirEntry *next;
  54. } dirEntry;
  55.  
  56. /**
  57.  | Global variables: Intuition pointers; the disk change
  58.  | number, and the total number of errors found reading files;
  59.  | the number of checked files and directories; and a flag
  60.  | "scheduled from WB or CLI".
  61. **/
  62.  
  63. struct MsgPort *diskPort = NULL;
  64. struct IOExtTD *diskReq = NULL;
  65. BYTE *diskBuffer = NULL;
  66. ULONG diskChangeCount;
  67. int nErFil = 0;
  68. int nDirs = 0;
  69. int nFiles = 0;
  70. Boolean fromWorkBench;
  71.  
  72. /**
  73.  | The ANSI procedure prototypes
  74. **/
  75.  
  76. void checkDir(char *path, Boolean root);
  77. void checkFile(char *name);
  78. void cleanup(int code);
  79. void motor(int action);
  80. void pcl(int n, char *fmt, ...);
  81. void readCyl(int cyl, int hd);
  82. void seekFullRange(SHORT howmany);
  83. void syntax(void);
  84.  
  85. main(
  86.   int argc,
  87.   char **argv
  88. ){
  89.   int drive, cyl, head;
  90.   SHORT error;
  91.   char driveName[5];
  92.  
  93. /**
  94.  | To be called from CLI, with DT DFx[:] ; if called from the
  95.  | Workbench, a prompt for the floppy unit is sent to the console
  96.  | window (created from the Lattice initialisation routine).
  97.  |  Pass 1: a seek over full range;
  98.  |  Pass 2: read all cylinders;
  99.  |  Pass 3: read all files record by record.
  100.  | But first, check the input arguments and open Intuition.
  101. **/
  102.  
  103.   fprintf(stdout, "\n\t\"DT\" - V%.2f MLO %d\n", VERSION, LAST_CHANGED);
  104.  
  105.   if (argc == 0) {
  106.     do {
  107.       fprintf(stdout, "\nDrive to test (DF0-DF4) ? ");
  108.       fgets(driveName, sizeof(driveName), stdin);
  109.     } while (strnicmp(driveName, "df", 2)   ||
  110.              (drive = atoi(driveName + 2)) < 0   ||   drive > 4);
  111.     fromWorkBench = True;
  112.   } else {
  113.     fromWorkBench = False;
  114.     if (argc != 2   ||   strnicmp(*++argv, "df", 2))    syntax();
  115.     if ((drive = atoi(*argv+2)) < 0   ||   drive > 4)   syntax();
  116.   }
  117.  
  118.   if ((diskBuffer = (BYTE *) AllocMem(TD_CYL, MEMF_CHIP)) == NULL) {
  119.     fprintf(stderr, "Can't allocate chip memory ...\n");
  120.     cleanup(SYS_ABORT_CODE);
  121.   }
  122.  
  123. /**
  124.  | Pass 1
  125. **/
  126.  
  127.   if (!(diskPort = (struct MsgPort *) CreatePort(0, 0))) {
  128.     fprintf(stderr, "Can't create I/O port ...\n");
  129.     cleanup(SYS_ABORT_CODE);
  130.   }
  131.  
  132.   if (!(diskReq = (struct IOExtTD *)
  133.       CreateExtIO(diskPort, sizeof(struct IOExtTD))) ) {
  134.     fprintf(stderr, "Can't obtain I/O request block ...\n");
  135.     cleanup(SYS_ABORT_CODE);
  136.   }
  137.  
  138.   sprintf(driveName, "DF%d:", drive);
  139.   if (error = OpenDevice(TD_NAME, drive, diskReq, 0)) {
  140.     fprintf(stderr,
  141.             "Error 0x%X returned by OpenDevice for drive %s ...\n",
  142.             error, driveName);
  143.     cleanup(SYS_ABORT_CODE);
  144.   }
  145.  
  146.   diskReq->iotd_Req.io_Command = TD_CHANGENUM;
  147.   DoIO(diskReq);
  148.   diskChangeCount = diskReq->iotd_Req.io_Actual;
  149.   fprintf(stdout, "\nChange number for drive %s is %d;\n",
  150.           driveName, diskChangeCount);
  151.   motor(ON);
  152.   seekFullRange(1);
  153.  
  154. /**
  155.  | Pass 2
  156. **/
  157.  
  158.   fprintf(stdout, "Checking all disk tracks:\n");
  159.   for (cyl=0; cyl<NUMCYLS; cyl++) {
  160.     for (head=0; head<NUMHEADS; head++) {
  161.       fprintf(stdout, "  reading cylinder %d, head %d ...\r", cyl, head);
  162.       readCyl(cyl, head);
  163.       if (error = diskReq->iotd_Req.io_Error) {
  164.         motor(OFF);
  165.         fprintf(stdout,
  166.                 "Error 0x%X detected for cylinder %d, head %d\n",
  167.                 error, cyl, head);
  168.         cleanup(SYS_ABORT_CODE);
  169.       }   
  170.     }
  171.   }
  172.   motor(OFF);
  173.   fprintf(stdout, "  no errors detected reading drive %s.\n", driveName);
  174.  
  175. /**
  176.  | Pass 3
  177. **/
  178.  
  179.   fprintf(stdout, "Checking all files in drive %s\n", driveName);
  180.   checkDir(driveName, True);
  181.   pcl(2, "%d director%s and %d file%s checked: %d error%s detected.",
  182.       nDirs, (nDirs == 1 ? "y" : "ies"),
  183.       nFiles, (nFiles == 1 ? "" : "s"),
  184.       nErFil, (nErFil == 1 ? "" : "s"));
  185.   cleanup(SYS_NORMAL_CODE);
  186. }
  187.  
  188. void checkDir(
  189.   char *path,
  190.   Boolean root
  191. ){
  192.   struct FILEINFO info;
  193.   char fileName[FILENAME_MAX];
  194.   int error;
  195.   dirEntry *rdE = NULL;
  196.   dirEntry *pdE;
  197.  
  198. /**
  199.  | Check a directory; path contains the full directory name, and root is
  200.  | non zero for the root directory. We scan all directory files, checking
  201.  | 'true' files at first and all subdirectories at the end, one by one.
  202. **/
  203.  
  204.   nDirs++;
  205.   pcl(1, "  checking files in%s directory %s ...",
  206.       (root ? " root" : ""), path);
  207.   strcpy(fileName, path);
  208.   strcat(fileName, (root ? "#?" : "/#?"));
  209.  
  210.   error = dfind(&info, fileName, True);
  211.   while (!error) {
  212.     strcpy(fileName, path);
  213.     if (!root) strcat(fileName, "/");
  214.     strcat(fileName, info.fib_FileName);
  215.     if (info.fib_DirEntryType < 0) {
  216.       checkFile(fileName);
  217.     } else {
  218.       if ((pdE = malloc(sizeof(dirEntry))) == NULL) {
  219.         fprintf(stderr, "Can't allocate heap memory ...\n");
  220.         cleanup(SYS_ABORT_CODE);
  221.       }
  222.       if ((pdE->name = malloc(strlen(fileName) + 1)) == NULL) {
  223.         fprintf(stderr, "Can't allocate heap memory ...\n");
  224.         cleanup(SYS_ABORT_CODE);
  225.       }
  226.       strcpy(pdE->name, fileName);
  227.       pdE->next = rdE;
  228.       rdE = pdE;
  229.     }
  230.     error = dnext(&info);
  231.   }
  232.  
  233.   while (rdE != NULL) {
  234.     checkDir(rdE->name, False);
  235.     free(rdE->name);
  236.     pdE = rdE->next;
  237.     free(rdE);
  238.     rdE = pdE;
  239.   }
  240. }
  241.  
  242. void checkFile(
  243.   char *name
  244. ){
  245.   struct FileHandle *pFH;
  246.   long ier;
  247.  
  248. /**
  249.  | Check a file, opening and reading record by record; this procedure
  250.  | is performed using the standard AmigaDOS disk file interface.
  251. **/
  252.  
  253.   nFiles++;
  254.   pcl(0, "    file %s ...", name);
  255.   if ((pFH = (struct FileHandle *) Open(name, MODE_OLDFILE)) == NULL) {
  256.     pcl(1, "* Error opening file \"%s\": file not found.", name);
  257.     nErFil++;
  258.   } else {
  259.     while ((ier = Read(pFH, diskBuffer, TD_CYL)) > 0) { }
  260.     if (ier < 0) {
  261.       pcl(1, "* AmigaDOS error %d reading file \"%s\".", IoErr(), name);
  262.       nErFil++;
  263.     }
  264.   }
  265.   Close(pFH);
  266. }
  267.  
  268. void cleanup(
  269.   int code
  270. ){
  271.   if (diskBuffer != NULL) {
  272.     FreeMem(diskBuffer, TD_CYL);
  273.   }
  274.   if (diskReq != NULL) {
  275.     CloseDevice(diskReq);
  276.     DeleteExtIO(diskReq, sizeof(struct IOExtTD));
  277.   }
  278.   if (diskPort != NULL)   DeletePort(diskPort);
  279.  
  280.   if (fromWorkBench) {
  281.     int i;
  282.     fprintf(stdout, "Strike <CR> to continue ...");
  283.     while ( (i = getchar()) != '\n'   &&   i != EOF)  { }
  284.   }
  285.   exit(code);
  286. }
  287.  
  288. void motor(
  289.   int action
  290. ){
  291.   diskReq->iotd_Req.io_Length = action;
  292.   diskReq->iotd_Req.io_Command = TD_MOTOR;
  293.   DoIO(diskReq);
  294. }
  295.  
  296. void pcl(
  297.   int n,
  298.   char *fmt,
  299.   ...
  300. ){
  301.   va_list vl;
  302.   static length = 0;
  303.   int nc;
  304.  
  305. /**
  306.  | What the hell is the delete-to-end-of-line sequence on the Amiga?
  307.  | The AmigaDOS manual refers to the ANSI sequence <ESC>[1K - that do
  308.  | not work in my NewCon windows; so I wrote this simple interface. When
  309.  | overprinting, we check if the length of the new line is greater than
  310.  | the old one - if not, we output some blanks. "n" is the number of
  311.  | newlines at the end, or zero for no newline but carriage return.
  312. **/
  313.  
  314.   va_start(vl, fmt);
  315.   nc = vfprintf(stdout, fmt, vl);
  316.   va_end(vl);
  317.   length -= nc;
  318.   if (length > 0) fprintf(stdout, "%*s", length, " ");
  319.   if (n) {
  320.     while (n--) fprintf(stdout, "\n");
  321.     length = 0;
  322.   } else {
  323.     fprintf(stdout, "\r");
  324.     length = nc;
  325.   }
  326. }
  327.  
  328. void readCyl(
  329.   int cyl, 
  330.   int hd
  331. ){
  332.   LONG offset;
  333.  
  334.   diskReq->iotd_Req.io_Length = TD_CYL;
  335.   diskReq->iotd_Req.io_Data = (APTR) diskBuffer;
  336.   diskReq->iotd_Req.io_Command = ETD_READ;
  337.   diskReq->iotd_Count = diskChangeCount;
  338.   offset = TD_SECTOR * (NUMSECS * (hd + NUMHEADS * cyl));
  339.   diskReq->iotd_Req.io_Offset = offset;
  340.   DoIO(diskReq);
  341. }
  342.  
  343. void seekFullRange(
  344.   SHORT howmany
  345. ){
  346.   int i;
  347.   SHORT error;
  348.  
  349.   for (i=1; i<=howmany; i++) {
  350.     diskReq->iotd_Req.io_Offset =
  351.           ((NUMCYLS - 1) * NUMSECS * NUMHEADS - 1) * TD_SECTOR;
  352.     diskReq->iotd_Req.io_Command = TD_SEEK;
  353.     DoIO(diskReq);
  354.     if (error = diskReq -> iotd_Req.io_Error) {
  355.       fprintf(stdout, "\nSeek cycle %d, error 0x%X ...\n", i, error);
  356.       cleanup(SYS_ABORT_CODE);
  357.     }
  358.  
  359.     diskReq->iotd_Req.io_Offset = 0;
  360.     diskReq->iotd_Req.io_Command = TD_SEEK;
  361.     DoIO(diskReq);
  362.     if (error = diskReq->iotd_Req.io_Error) {
  363.       fprintf(stdout, "\nSeek cycle %d, error 0x%X ...\n", i, error);
  364.       cleanup(SYS_ABORT_CODE);
  365.     }
  366.   }
  367.   fprintf(stdout, "no errors detected seeking over full disk range.\n");
  368. }
  369.  
  370. void syntax(void)
  371. {
  372.   fprintf(stdout,
  373.         "\n\tUsage:\t\tDT DFn, where 'n' (0-4) is the drive number.\n");
  374.   fprintf(stdout,
  375.         "\tPurpose:\tDisk test.\n\n");
  376.   cleanup(SYS_NORMAL_CODE);
  377. }
  378.